/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package hpssim;

import java.util.ArrayList;
import javax.print.attribute.standard.Sides;

/**
 *
 * @author fla
 */
public class Scheduler {
    public Scheduler (int _type){
        type = _type;
    }
    
    /*
     * Other methods such as recalculate priority of all job 
     */
    public void enqueue(EventList evl, Event ev, DeviceList hw, Queue q){
        Event ev1; 
        q.push(ev.job);       
        ev1 = new Event(null, Event.RUN, ev.time);
        evl.insertEvent(ev1);
        System.out.print("RUN " + ev.time+ " " + hw.getCPUfree()+" "+ hw.getGPUfree() +" " + q.size()+ " ");        
        
    } 
    
    public void run(EventList evl, Event ev, DeviceList hw, Queue q){
        //System.out.println("RUN");
        Event ev1;
        int indexGPUjob;
        boolean gpurun = false;        
        Job j;
        if (hw.getCPUfree() == 0){
            ev1 = new Event(null, Event.RESCHEDULE, ev.time+1);            
            System.out.print("RESCHEDULE " + (ev.time+1) + " " + q.size()+ " ");
            evl.insertEvent(ev1);
        }
        else{
            while( (hw.getCPUfree() > 0) && (q.size() > 0) ){                            
                    indexGPUjob = q.getIndexFirstGPUjob();
                    //System.out.print(" q.size " + q.size()+ " ");
                    if ( indexGPUjob >=0 && hw.getGPUfree() > 0 ){                        
                        j = q.getJob(indexGPUjob);
                        //System.out.print(" GPU cado qui gpurun jid " +j.getid()+" ");
                        gpurun = true;
                    }else{
                        gpurun = false;
                        j = q.pop();                        
                    }
                    if (j.rescheduled==0){ // if first execution set start run time, remaning time
                        j.sette(ev.time);
                        j.settq(ev.time);
                        
                        if (gpurun) {
                            //System.out.print(" GPU ");
                            j.settrem(j.rgpu);
                        }
                        else{
                            j.settrem(j.rcpu);
                        }
                    }
                    if (gpurun){
                        //System.out.println("GPUJOB" + gpurun);
                        hw.assignJobtoGPU(j);
                    }
                    else{
                        hw.assignJobtoCPU(j);
                    }
                    if ((j.trem > Simulator.tq) && (!gpurun)) { 
                        //REQUEUE  //SETTA LA NUOVA PRIORITA' //SETTA IL TEMPO RIMANENTE                   
                        //j.rescheduled++;                        
                        ev1 = new Event(j, Event.REQUEUE, ev.time+Simulator.tq);
                        System.out.print("REQUEUE " + (ev.time+Simulator.tq) + " "+ hw.getCPUfree()+" "+ hw.getGPUfree() + " " + q.size()+ " ");
                        evl.insertEvent(ev1);
                    }
                    else { // FINALIZE                   
                        ev1 = new Event(j, Event.FINALIZE, ev.time+j.trem);                   
                        System.out.print("FINALIZE " + (ev.time+j.trem) + " "+ hw.getCPUfree()+" "+ hw.getGPUfree() + " " + q.size()+ " ");
                        evl.insertEvent(ev1);
                    }
                }                                                
        }                
    }
    
    public Event requeue(EventList evl, Event ev, DeviceList hw, Queue q){
        //System.out.println("REQUEUE");
        System.out.print("ENEQUEUE " + (ev.time) + " " + hw.getCPUfree()+" "+ hw.getGPUfree() +" " + q.size()+ " ");
        Event ev1; 
        Job j = hw.teminate(ev.job.getid());
        j.setps(j.getps()- 5);
        j.trem -= Simulator.tq;
        j.te += Simulator.tq;
        j.rescheduled++;
        ev1 = new Event(j, Event.ENQUEUE, ev.time);
        evl.insertEvent(ev1);
        return ev1;
    }
    
    public void reschedule(EventList evl, Event ev, DeviceList hw, Queue q){
        Event ev1;
        q.newpriority();      
        ev.time += 0;
        ev1 = new Event(null, Event.RUN, ev.time);
        evl.insertEvent(ev1);
        System.out.print("RUN " + ev.time + " " + hw.getCPUfree()+" "+ hw.getGPUfree() + " " + q.size()+ " ");
    }
    public void finalize(EventList evl, Event ev, DeviceList hw, Queue q, Queue result){
        Job j;
        Event ev1;
        j = hw.teminate(ev.job.id);
        j.te += j.trem;
        j.trem = 0;
        j.settfinalize(ev.time);
        // add job to terminated job for stats
        result.push(j);
        ev1 = new Event(null, Event.RESCHEDULE, ev.time+1);
        evl.insertEvent(ev1);
        System.out.print("null " + "n/a" + " " + hw.getCPUfree()+" "+ hw.getGPUfree() + " " + q.size()+ " ");
        System.out.print("Queue | ");
        q.printjob();
    }
    private int type;
    public final static int FIFO = 0;
    public final static int RR = 1;
    public final static int PR = 2;
}
